package com.swak.boot.config.vertx;

import java.util.List;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.swak.OS;
import com.swak.boot.config.customizer.VertxOptionsCustomizer;
import com.swak.reactivex.transport.TransportMode;
import com.swak.vertx.Vertxs;
import com.swak.vertx.config.VertxConfig;
import com.swak.vertx.transport.VertxProxy;
import com.swak.vertx.transport.server.ReactiveServer;
import com.swak.vertx.transport.vertx.StandardVertx;

import io.vertx.core.file.FileSystemOptions;

/**
 * 配置单机版本的 vertx
 * 
 * @author lifeng
 */
@Configuration
@ConditionalOnClass(ReactiveServer.class)
@ConditionalOnMissingBean(StandardVertx.class)
@EnableConfigurationProperties(VertxProperties.class)
public class StandardVerxAutoConfiguration {

	protected static boolean isWeb = true;

	static {
		try {
			Class.forName("io.vertx.ext.web.RoutingContext");
		} catch (Exception e) {
			isWeb = false;
		}
	}

	public StandardVerxAutoConfiguration() {
		System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
		System.setProperty("vertx.disableDnsResolver", "true");
	}

	/**
	 * 配置标准的 vertx
	 * 
	 * @param properties
	 * @return
	 */
	@Bean
	public VertxProxy standardVertx(VertxProperties properties,
			ObjectProvider<List<VertxOptionsCustomizer>> customizersProvider) {

		VertxConfig vertxOptions = new VertxConfig();
		if (properties.getMode() == TransportMode.EPOLL) {
			vertxOptions.setPreferNativeTransport(true);
		}
		// HttpHandlers 根据 HttpServerImpl 的值 DISABLE_WEBSOCKETS 来判断 是否需要禁用 websocket
		// 目前是无法自定义的， 可以在真实启用 Websocket 在开启这个参数
		if (!properties.isEnableWebsocket()) {
			System.setProperty("vertx.disableWebsockets", Boolean.TRUE.toString());
		}
		if (!properties.isUseAlpn()) {
			System.setProperty("vertx.disableH2c", Boolean.TRUE.toString());
		}
		// threadCache
		if (!properties.isThreadCache()) {
			System.setProperty("io.netty.allocator.tinyCacheSize", "0");
			System.setProperty("io.netty.allocator.smallCacheSize", "0");
			System.setProperty("io.netty.allocator.normalCacheSize", "0");
		}
		// leakDetection
		if (properties.getLeakDetectionLevel() != null) {
			System.setProperty("io.netty.leakDetection.level", properties.getLeakDetectionLevel().name());
		}
		vertxOptions.setEventLoopPoolSize(properties.getEventLoopPoolSize());
		vertxOptions.setWorkerPoolSize(properties.getWorkerPoolSize());
		vertxOptions.setInternalBlockingPoolSize(properties.getInternalBlockingThreads());
		vertxOptions.setMaxEventLoopExecuteTime(properties.getMaxEventLoopExecuteTime());
		vertxOptions.setMaxWorkerExecuteTime(properties.getMaxWorkerExecuteTime());
		vertxOptions.setDisableTCCL(true);
		FileSystemOptions fileSystemOptions = new FileSystemOptions();
		fileSystemOptions.setClassPathResolvingEnabled(properties.isClassPathResolvingEnabled());
		fileSystemOptions.setFileCachingEnabled(properties.isFileCachingEnabled());
		fileSystemOptions.setFileCacheDir(properties.getFileCacheDir());
		vertxOptions.setFileSystemOptions(fileSystemOptions);

		List<VertxOptionsCustomizer> customizers = customizersProvider.getIfAvailable();
		if (customizers != null && !customizers.isEmpty()) {
			for (VertxOptionsCustomizer customizer : customizers) {
				customizer.customize(vertxOptions);
			}
		}

		vertxOptions.setHost(properties.getHost());
		vertxOptions.setPort(properties.getPort());
		vertxOptions.setWebSocketPort(properties.getWebSocketPort());
		vertxOptions.setWebSocketHeartbeatMs(properties.getWebSocketHeartbeatMs());
		vertxOptions.setKeyStorePass(properties.getKeyStorePass());
		vertxOptions.setKeyStorePath(properties.getKeyStorePath());
		vertxOptions.setKeyStoreAlgorithm(properties.getKeyStoreAlgorithm());
		vertxOptions.setTokenName(properties.getTokenName());
		vertxOptions.setTokenExpiresInSeconds(properties.getTokenExpiresInSeconds());
		vertxOptions.setUploadDirectory(properties.getUploadDirectory());
		vertxOptions.setBodyLimit(properties.getBodyLimit());
		vertxOptions.setDeleteUploadedFilesOnEnd(properties.isDeleteUploadedFilesOnEnd());
		vertxOptions.setCompressionLevel(properties.getCompressionLevel());
		vertxOptions.setCompressionSupported(properties.isCompressionSupported());
		vertxOptions.setKeyPaths(properties.getKeyPaths());
		vertxOptions.setUseSsl(properties.isUseSsl());
		vertxOptions.setUseAlpn(properties.isUseAlpn());
		vertxOptions.setCertPaths(properties.getCertPaths());
		vertxOptions.setClientAuth(properties.getClientAuth());
		vertxOptions.setSendTimeout(properties.getSendTimeout());

		vertxOptions.setMaxHeaderSize(properties.getMaxHeaderSize());
		vertxOptions.setMaxFormAttributeSize(properties.getMaxFormAttributeSize());

		if (!isWeb) {
			vertxOptions.setEventLoopPoolSize(1);
		}

		// 设置随机端口
		if (vertxOptions.getPort() <= 0) {
			vertxOptions.setPort(OS.randomAvailablePort());
		}
		if (vertxOptions.getWebSocketPort() <= 0) {
			vertxOptions.setPort(OS.randomAvailablePort());
		}
		return new StandardVertx(vertxOptions);
	}

	/**
	 * 全局的 Vertxs
	 * 
	 * @param proxy
	 * @return
	 */
	@Bean
	public Vertxs vertxs(VertxProxy proxy) {
		return new Vertxs(proxy);
	}
}